-
Notifications
You must be signed in to change notification settings - Fork 123
check body length #255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
check body length #255
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Looks like a great start but I think there's some EL confusion and lacking assertions.
@@ -794,11 +796,19 @@ extension TaskHandler: ChannelDuplexHandler { | |||
assert(head.version == HTTPVersion(major: 1, minor: 1), | |||
"Sending a request in HTTP version \(head.version) which is unsupported by the above `if`") | |||
|
|||
self.expectedBodyLength = head.headers[canonicalForm: "content-length"].first.flatMap { Int($0) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to error if there's more than one CL header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't validateHeaders
do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add a return from validate
with body length, as an alternative
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy if we have a test that proves that we error if the user sends two content-length
s. In this code, I think we should just add an
assert(head.headers[canonicalForm: "content-length"].count <= 1)
to be sure. That makes the code much easier to read because you can immediately dismiss that thought if you see the assertion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's even better, we remove all content length headers and insert them ourselves :) except one case, I'll add a test for that (and an assert).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will happen only if the stream has no length is not specified. In all other cases we actually ignore the user-provided headers, you think we should fail on those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@artemredkin wait, why are we looking for the first CL header then if this code is only run if the user specified no CL headers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code is run always, if the content-length was not specified, then expectedLength
will be nil
and final check will not be executed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alright, let's just add the assertion&test (if not present for all the possible cases) in case somebody modifies the sanitisation code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
@@ -836,6 +846,7 @@ extension TaskHandler: ChannelDuplexHandler { | |||
} | |||
|
|||
return promise.futureResult.map { | |||
self.actualBodyLength += part.readableBytes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- assertion about the correct EL missing
- test that would fail this assertion right now probably missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved the increment to where it is certainly on correct EL
XCTAssertEqual(error as! HTTPClientError, HTTPClientError.bodyLengthMismatch) | ||
} | ||
// Quickly try another request and check that it works. | ||
XCTAssertNoThrow(try self.defaultClient.get(url: self.defaultHTTPBinURLPrefix + "/get").wait()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I know I wrote this test but we should check the correct connectionNumber
and requestNumber
from
internal struct RequestInfo: Codable {
var data: String
var requestNumber: Int
var connectionNumber: Int
}
just to be sure we get a fresh connection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, do we even need this part? we already have a test that checks that, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I think I know what you mean!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
} | ||
// Quickly try another request and check that it works. If we by accident wrote some extra bytes into the | ||
// stream (and reuse the connection) that could cause problems. | ||
XCTAssertNoThrow(try self.defaultClient.get(url: self.defaultHTTPBinURLPrefix + "/get").wait()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar here, we should validate request/connection number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
@@ -357,8 +361,8 @@ internal struct HTTPResponseBuilder { | |||
} | |||
} | |||
|
|||
let globalRequestCounter = NIOAtomic<Int>.makeAtomic(value: 0) | |||
let globalConnectionCounter = NIOAtomic<Int>.makeAtomic(value: 0) | |||
//let globalRequestCounter = NIOAtomic<Int>.makeAtomic(value: 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, fixed, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! LGTM
@swift-server-bot test this please |
c161ff5
to
610af18
Compare
610af18
to
715ab14
Compare
@swift-server-bot test this please |
Adds checking for supplied body length.
Motivation:
We need to guard against incorrect body length since we can re-use connection, this is a potential security issue.
Modifications:
HTTPTaskHandler
that if validated headers containContent-Length
, user sends exactly that amount of body data.Result:
Closes #251